#include "SerialPort.hpp"
#include "stdio.h"
/*  库文件  */
#include "usart.h"

#define SERIALPORT_NUMBER   6 + 1   //  串口数 串口从1开始 但是索引从0开始
#define MAX_DATA_LENGTH 64          //  数据接收最大长度

struct USARTHardwareConfig{
    UART_HandleTypeDef * usart;
};

static USARTHardwareConfig usart_configs[SERIALPORT_NUMBER];

static USARTHardwareConfig usart_config_1 = {
    .usart = &huart1,
};

/*  配置指定串口的硬件参数并使能接收中断（目前仅支持串口1） */
bool  configure_usart(int port_number) {
    if( port_number == 1 ){
        usart_configs[port_number] = usart_config_1;
        __HAL_UART_ENABLE_IT(usart_configs[port_number].usart, UART_IT_RXNE);
    }
    else{
        return false;
    }
    return true;
}

/*  串口类的实现  */
class _SerialPort : public SerialPort{
public:
    _SerialPort(unsigned char serial_port_number);
    virtual bool init();
    virtual int send(void *data,int length);
    virtual int receive(void *data);

    void interruptHandler();

private:
    QueueHandle_t usart_queue = NULL;
    SemaphoreHandle_t usart_semaphore = NULL;
};

/* 定义静态实例数组 */
static _SerialPort _serial_port_instances[SERIALPORT_NUMBER] = {
    _SerialPort(0),
    _SerialPort(1),
    _SerialPort(2),
    _SerialPort(3),
    _SerialPort(4),
    _SerialPort(5),
    _SerialPort(6),
};

/* 获取串口实例 */
static _SerialPort * serial_port[SERIALPORT_NUMBER] = {nullptr};

/* 使用成员初始化列表将参数 serial_port_number 初始化到成员变量 port_number */
SerialPort::SerialPort(unsigned char serial_port_number):port_number(serial_port_number){}

/* 获取指定编号的串口单例对象，若未初始化则进行初始化 */
SerialPort * SerialPort::getInstance(unsigned char serial_port_number){
    if (serial_port_number >= SERIALPORT_NUMBER) {
        return nullptr;
    }
    
    if (serial_port[serial_port_number] == nullptr) {
        serial_port[serial_port_number] = &_serial_port_instances[serial_port_number];
        serial_port[serial_port_number]->init();
    }
    
    return serial_port[serial_port_number];
}

/*  _SerialPort 构造函数，调用基类 SerialPort 的构造函数初始化串口编号 */
_SerialPort::_SerialPort(unsigned char serial_port_number) : SerialPort(serial_port_number){}

bool _SerialPort::init(){

    configure_usart(port_number);
    usart_queue = xQueueCreate(MAX_DATA_LENGTH , sizeof(unsigned char));
    if( usart_queue == NULL ){
        return false;
    }
    usart_semaphore = xSemaphoreCreateCounting(MAX_DATA_LENGTH , 0 );
    if( usart_semaphore == NULL ){
        return false;
    }
    return true;
}

int _SerialPort::send(void *data,int length){
    unsigned char * send_data = reinterpret_cast<unsigned char *>(data);
    if( usart_configs[port_number].usart != nullptr ){
        HAL_UART_Transmit(usart_configs[port_number].usart,reinterpret_cast<unsigned char*>(send_data),length,HAL_MAX_DELAY);
        return length;
    }else{
        return 0;
    }
}

const int WAIT_TIME = 10;   // 等待时间 单位是时钟周期
int _SerialPort::receive(void *data){
    int index = 0;
    unsigned char *rxbuffer = (unsigned char *)data;
    while( xSemaphoreTake(usart_semaphore , WAIT_TIME) == pdTRUE ){
        if (xQueueReceive(usart_queue, &rxbuffer[index], WAIT_TIME) == pdTRUE){
            index ++ ;
        }
    }
    return index;

}

void _SerialPort::interruptHandler() {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t result;
    if (__HAL_UART_GET_FLAG(usart_configs[port_number].usart, UART_FLAG_RXNE) != RESET ){
        unsigned char data = usart_configs[port_number].usart->Instance->DR;
        xQueueSendFromISR(usart_queue, &data, &xHigherPriorityTaskWoken);
        xSemaphoreGiveFromISR(usart_semaphore , &xHigherPriorityTaskWoken);
    }
}


extern "C"
void USART1_IRQHandler(void){
    if ( __HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET ){
        if ( serial_port[1] != nullptr ){
            serial_port[1]->interruptHandler();
        }
    }
}
